﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls;
using System.Windows.Input;
using IronCow;
using Milkify.Data;
using Milkify.Input;
using Milkify.Interfaces;
using System.ComponentModel;

namespace Milkify.Views
{
    /// <summary>
    /// Interaction logic for TaskListControl.xaml
    /// </summary>
    public partial class TaskListControl : Page, ITaskListView, ISuggestsTaskList, ISuggestsTaskEditValues, INotifyPropertyChanged
    {
        private PageFocusHelper mFocusHelper;

        private bool mSelectedTasksAreCompleted = false;
        public bool SelectedTasksAreCompleted
        {
            get { return mSelectedTasksAreCompleted; }
            private set
            {
                mSelectedTasksAreCompleted = value;
                OnPropertyChanged("SelectedTasksAreCompleted");
            }
        }

        private bool mSelectedTasksAreIncomplete = false;
        public bool SelectedTasksAreIncomplete
        {
            get { return mSelectedTasksAreIncomplete; }
            private set
            {
                mSelectedTasksAreIncomplete = value;
                OnPropertyChanged("SelectedTasksAreIncomplete");
            }
        }

        public TaskListControl()
        {
            InitializeComponent();

            ListTasks.KeyDown += new KeyEventHandler(ListTasks_KeyDown);
            ListTasks.SelectionChanged += new SelectionChangedEventHandler(ListTasks_SelectionChanged);

            TaskListSort = (TaskListSort)Enum.Parse(typeof(TaskListSort), Properties.Settings.Default.DefaultTaskListSorting);
            IsTaskListSortReversed = Properties.Settings.Default.IsDefaultTaskListSortingInversed;

            mFocusHelper = new PageFocusHelper(this, ListTasks);
        }

        private void ListTasks_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter || e.Key == Key.Return)
            {
                // On Enter/Return, programmatically perform a click on the focused task button.
                var originalSource = e.OriginalSource as ListBoxItem;
                if (originalSource != null)
                {
                    var button = FocusHelper.FindVisualChild<Button>(originalSource);
                    if (button != null)
                    {
                        var buttonPeer = UIElementAutomationPeer.CreatePeerForElement(button);
                        var invokeProvider = buttonPeer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
                        if (invokeProvider != null)
                            invokeProvider.Invoke();
                    }
                }
            }
        }

        private void ListTasks_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var tasks = GetCurrentSelection();
            if (tasks.Length == 0)
            {
                SelectedTasksAreCompleted = false;
                SelectedTasksAreIncomplete = false;
            }
            else
            {
                bool? allIncomplete = tasks[0].IsIncomplete;
                foreach (var task in tasks)
                {
                    if (task.IsIncomplete != allIncomplete)
                    {
                        allIncomplete = null;
                        break;
                    }
                }
                if (allIncomplete.HasValue)
                {
                    SelectedTasksAreCompleted = !allIncomplete.Value;
                    SelectedTasksAreIncomplete = allIncomplete.Value;
                }
                else
                {
                    SelectedTasksAreCompleted = false;
                    SelectedTasksAreIncomplete = false;
                }

            }
        }
        
        private void ComboSort_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (TaskListSortChanged != null)
                TaskListSortChanged(this, EventArgs.Empty);
        }

        private void HyperlinkAscOrDesc_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
        {
            if (TextAscOrDesc.Text == "ascending")
                TextAscOrDesc.Text = "descending";
            else
                TextAscOrDesc.Text = "ascending";

            IsTaskListSortReversed = !IsTaskListSortReversed;

            if (TaskListSortChanged != null)
                TaskListSortChanged(this, EventArgs.Empty);
        }

        private void ComboFilter_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (TaskListFilterChanged != null)
                TaskListFilterChanged(this, EventArgs.Empty);
        }

        private void ButtonTask_Click(object sender, RoutedEventArgs e)
        {
            var button = sender as Button;
            var listBoxItem = ListTasks.ItemContainerGenerator.ContainerFromItem(button.DataContext) as ListBoxItem;
            mFocusHelper.FocusElement = listBoxItem;
        }

        #region IView Members

        public object ViewData
        {
            get { return DataContext; }
            set
            {
                DataContext = value;

                // Set the title of this view to be the name of the requested TaskList, if any.
                var data = DataContext as TaskListViewData;
                if (data != null)
                {
                    Title = data.ListName;
                }
                else
                {
                    Title = "Tasks";
                }
            }
        }

        #endregion

        #region IRefreshableView Members

        public bool NeedsRefresh { get; set; }

        #endregion

        #region ITaskListView Members

        public bool IsTaskListSortReversed { get; set; }

        public TaskListSort TaskListSort
        {
            get { return (TaskListSort)ComboSort.SelectedValue; }
            set { ComboSort.SelectedValue = value; }
        }

        public TaskListFilter TaskListFilter
        {
            get { return (TaskListFilter)ComboFilter.SelectedValue; }
            set { ComboFilter.SelectedValue = value; }
        }

        public event EventHandler TaskListSortChanged;
        public event EventHandler TaskListFilterChanged;

        public Task[] GetCurrentSelection()
        {
            var tasks = new List<Task>();
            foreach (Task task in ListTasks.SelectedItems)
            {
                tasks.Add(task);
            }
            return tasks.ToArray();
        }

        #endregion

        #region ISuggestsTaskList Members

        public IronCow.TaskList SuggestedTaskList
        {
            get
            {
                TaskListViewData viewData = ViewData as TaskListViewData;
                if (viewData == null)
                    return null;
                return viewData.TaskList;
            }
        }

        #endregion

        #region ISuggestsTaskEditValues Members

        private IEnumerable<T> CollectNodes<T>(IronCow.Search.Node node) where T : IronCow.Search.Node
        {
            var filteredNodes = new List<T>();
            var nodeStack = new Stack<IronCow.Search.Node>();
            nodeStack.Push(node);
            while (nodeStack.Count > 0)
            {
                var currentNode = nodeStack.Pop();
                if (currentNode is T)
                    filteredNodes.Add((T)currentNode);

                foreach (var n in currentNode)
                {
                    nodeStack.Push(n);
                }
            }
            return filteredNodes;
        }

        public void InsertSuggestedValues(ITaskEditView view)
        {
            TaskListViewData viewData = ViewData as TaskListViewData;
            if (viewData == null)
                return;

            if (viewData.TaskList != null)
                view.SuggestTaskList(viewData.TaskList);

            if (!string.IsNullOrEmpty(viewData.SearchQuery))
            {
                var lexicalAnalyzer = new IronCow.Search.LexicalAnalyzer();
                var tokens = lexicalAnalyzer.Tokenize(viewData.SearchQuery);
                var astRoot = lexicalAnalyzer.BuildAst(tokens);
                var operatorNodes = CollectNodes<IronCow.Search.OperatorNode>(astRoot);

                var dueNodes = operatorNodes.Where(n => n.Name == "due");
                if (dueNodes.Count() == 1)
                    view.SuggestDueDate(dueNodes.First().Argument);
                var estimateNodes = operatorNodes.Where(n => n.Name == "timeEstimate");
                if (estimateNodes.Count() == 1)
                    view.SuggestEstimate(estimateNodes.First().Argument);
                var priorityNodes = operatorNodes.Where(n => n.Name == "priority");
                //TODO
                var tagNodes = operatorNodes.Where(n => n.Name == "tag");
                if (tagNodes.Count() == 1)
                    view.SuggestTags(tagNodes.First().Argument);
                var locationNodes = operatorNodes.Where(n => n.Name == "location");
                //TODO
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
